home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / DEMO_VGA / PYRO.LZH / PYRO.C < prev    next >
C/C++ Source or Header  |  1988-08-07  |  47KB  |  1,497 lines

  1. char c1[]="PYRO - A Simulated Pyrotechnics Display",
  2.      c2[]="Version 2.03  08/08/88",
  3.      c3[]="(c) 1988 K.G. Shields.";
  4.  
  5. /*
  6.  
  7. This program is a major revision of PYRO, the program that won the 1987 "Your
  8. Computer" Microsoft Computer Program Art Competition.  A number of features
  9. have been added that could not be included in PYRO version 1.00 because of
  10. the 199 line length limit imposed by the competition.
  11.  
  12. Additions include:
  13.  
  14. . An opening screen.
  15.  
  16. . A new effect - Catherine wheels.
  17.  
  18. . CGA and text-only displays are supported.
  19.  
  20. . The program detects processor speed and adjusts delay loops to compensate.
  21.   It also synchronizes itself with the timer tick of the machine.  Both these
  22.   actions are necessary to generate a smooth display and reasonable sound
  23.   effects.  The number of points used per effect may also be reduced, from a
  24.   maximum of 60 down as far as about 24 if necessary.
  25.  
  26. . The program has been optimized considerable including trade-offs of size
  27.   for speed, and can now run on a much wider range of machines.  On very
  28.   slow machines it switches from the standard script to a simplified one
  29.   which limits the amount of simultaneous screen activity that can occur.
  30. */
  31.  
  32. /* Timing results (with synch=0 and tot_loop=0) - ratio of unrestrained
  33. execution to desired execution time.  These are used to calculate delay
  34. loop values which compensate for the differing speeds of various machines.
  35. These values were obtained using version 2.00.
  36.  
  37. np      Display      NEC Powermate    Cleveland AT
  38.                        31/01/88         01/02/88
  39. 60      EGA             0.911            0.888
  40. 30      CGA             0.543            0.541
  41. 30      TEXT            0.274            0.274
  42. 60      suppressed      0.309            0.308
  43. 30      suppressed      0.171            0.181
  44.  
  45. Clock calls/timer tick    339              330
  46. */
  47.  
  48. #if !(defined(MSC) || defined(QUICKC) || defined(TURBOC))
  49.     /* One only of the following should be non-zero */
  50.     #define MSC     0    /* Microsoft Optimizing C Compiler */
  51.     #define QUICKC  1    /* Microsoft Quick C */
  52.     #define TURBOC  0    /* Turbo C */
  53. #endif
  54.  
  55. #define ref_ega 0.911
  56. #define ref_cga 0.543
  57. #define ref_text 0.274
  58. #define ref_herc 0.543 /* A first guess */
  59. #define ref_60 0.309
  60. #define ref_30 0.171
  61. #define ref_count 339
  62.  
  63. #if MSC || QUICKC
  64.     #include <stdlib.h>
  65.     #include <dos.h>
  66.     #include <math.h>
  67.     #include <stdio.h>
  68.     #include <conio.h>
  69. #elif TURBOC
  70.     #include <stdlib.h>
  71.     #include <dos.h>
  72.     #include <math.h>
  73.     #define outpw outport
  74. #endif
  75.  
  76. /* The following factors 'correct' the speed estimates to allow for the fact
  77. that some compilers generate better optimized code in the speed estimation
  78. routine than they do in the remainder of the program, and vice versa.  The
  79. REPCOR values are reasonably accurate, but the CALCCOR values are still
  80. only best guesses.*/
  81. #if MSC
  82.     #define REPCOR 0.695
  83.     #define CALCCOR 0.7
  84. #elif QUICKC
  85.     #define REPCOR 1.076
  86.     #define CALCCOR 0.65
  87. #elif TURBOC
  88.     #define REPCOR 1.0
  89.     #define CALCCOR 1.0
  90. #endif
  91.  
  92. #define NI 6 /*Number of items that may exist simultaneously*/
  93. #define TP 400 /*Total number of points*/
  94. #define UNKNOWN -1
  95. #define VGA 0
  96. #define EGA 1
  97. #define CGA 2
  98. #define MDA 3
  99. #define HGC 4
  100.  
  101. #define COLOUR 0
  102. #define MONO 1
  103.  
  104. #define EGM 0
  105. #define CGM 1
  106. #define TXTM 2
  107. #define HGCM 3
  108.  
  109. #define STANDARD 0
  110. #define SIMPLE 1
  111.  
  112. void (*show)();
  113.  
  114. union REGS inr,outr;
  115.  
  116. char far *bytepointer,far *egapointer,far *cgapointer,far *hgcpointer,far *cgapointer0,
  117.     far *cgapointer1,far *txtpointer,far * hgcpointers[4];
  118.  
  119. unsigned int address_6845,far *wordpointer;
  120.  
  121. char inkey,txt[]="THE END",cpoint[]=" .+*@@@@@@@",restore_screen[4000],
  122.     *ddesc[]={"VGA","EGA","CGA","MDA","HERCULES"},
  123.     *sdesc[]={"COLOUR","MONOCHROME"},
  124.     *mdesc[]={"EGA","CGA","TEXT","HERCULES"};
  125.  
  126. int xl[NI],xh[NI],yl[NI],yh[NI],vell[NI],velh[NI],angl[NI],angh[NI],alivel[NI],
  127.     aliveh[NI],coll[NI],colh[NI],sizev[NI],fadev[NI],item_alive[NI],
  128.     devicetype[NI],wait[NI],master[NI],xref[NI],yref[NI],wheelstep[NI],
  129.     wheelrep[NI],pdormant[NI],
  130.     g[TP],x[TP],y[TP],xvel[TP],yvel[TP],alive[TP],col[TP],size[TP],fade[TP],
  131.     itemno[TP],next[TP],state[TP],rowaddress[350],col_table[16],
  132.     adapter,screen,mode,sc_xmax,sc_ymax,margin,baseline,sp_vl,sp_vh,fl_vl,fl_vh,
  133.     rk_vl,rk_vh,rktail_vl,rktail_vh,ro_vl,ro_vh,wh_vl,wh_vh,sh,shx,shy,address,
  134.     oty_fac,ot_size,etx_off,etx_f1,etx_f2,ety_off,ety_fac,tr_l,tr_h,t_s,t_f,ro_rad,
  135.     continuous,burstwait,fullspeed,testcapacity,
  136.     spread,cga_palette,swap_flag,swaplevel,mincol,maxcol,endcol,count,report,quiet,
  137.     hs,ms,ss,he,me,se,stime,etime,extime,tot_loop,indep,per_point,slow1,synch,
  138.     np,im,jm,km,xmin,xmax,ymin,ymax,xend,yend,newpt,endpt,ci,state2,fl_mask,
  139.     num_active,pfree,pactive,num_dormant,mastercol,wheelradius,capacity,est_capacity,
  140.     wheelstepv,wheelreplim,wheelsteplim,wh_mask,excount,script,rep_tot_loop,
  141.     spurt=1,flare=2,burst=3,rocket=4,roman=5,wheel=6,
  142.     gv=2,burstlife=10,
  143.     noise=0;
  144.  
  145. float sina[401],cosa[401],t_slope,t_intercept;
  146.  
  147. unsigned long ticks1,ticks2;
  148.  
  149. void gotoxy(int col, int row) /* Moves the cursor to a specific column and row */
  150. {
  151.     inr.h.ah=2;
  152.     inr.h.bh=0;
  153.     inr.x.dx=((row-1)<<8)+col-1;
  154.     int86(0X10,&inr,&outr);
  155. } /*End gotoxy*/
  156.  
  157. void put_string(char *str,int col,int x,int y) /* Put string on screen at x,y*/
  158. {
  159.     static int i,j,k;
  160.     static char far *bytepointer;
  161.     if (mode==HGCM)
  162.     {
  163.  
  164.     bytepointer=(char far *)0xf0000000;
  165.     for (i=0;i<=strlen(str);i++)
  166.     {
  167.         if (str[i]!=' ')
  168.         for (j=7;j>=0;j--)
  169.             for (k=0;k<=7;k++)
  170.             if ((bytepointer[0xfa6e+j+8*str[i]] & (0x80>>k))>0)
  171.             {
  172.                 show((9*(x+i)+k)<<sh,(13*y+j)<<sh,1,1,1);
  173.  
  174.             }
  175.     }
  176.  
  177.     }
  178.     else
  179.     {
  180.     for (i=0;i<strlen(str);i++)
  181.     {
  182.         gotoxy(x+i,y);
  183.         inr.h.ah=9;
  184.         inr.h.al=str[i];
  185.         inr.h.bh=0;
  186.         inr.x.cx=1;
  187.         inr.h.bl=col;
  188.         int86(0x10,&inr,&outr);
  189.     }
  190.     }
  191. } /*End put_string*/
  192.  
  193. unsigned long get_ticks() /* Get current timer tick count*/
  194. {
  195.     inr.h.ah=0;
  196.     int86(0x1a,&inr,&outr);
  197.     return (unsigned long)outr.x.cx<<16 | outr.x.dx;
  198. } /*End get_ticks*/
  199.  
  200. void terminate();
  201.  
  202. void setrange(int *d1,int *d2,int s1,int s2) /*Store limits information*/
  203. {
  204.     if (s1<=s2)
  205.     {
  206.         *d1=s1;
  207.         *d2=s2;
  208.     } else {
  209.         *d1=s2;
  210.         *d2=s1;
  211.     }
  212. } /*End setrange*/
  213.  
  214. void limits(int it,int lxl,int lxh,int lyl,int lyh,int lvell,int lvelh,int langl,int langh,int lalivel,int laliveh,
  215. int lcoll,int lcolh,int lsize,int lfade) /*Set limits for point generation for item it*/
  216. {
  217.     setrange(&xl[it],&xh[it],lxl<<sh,lxh<<sh);
  218.     setrange(&yl[it],&yh[it],lyl<<sh,lyh<<sh);
  219.     setrange(&vell[it],&velh[it],lvell<<sh,lvelh<<sh);
  220.     setrange(&angl[it],&angh[it],langl,langh);
  221.     setrange(&alivel[it],&aliveh[it],lalivel,laliveh);
  222.     setrange(&coll[it],&colh[it],lcoll,lcolh);
  223.     sizev[it]=lsize;
  224.     fadev[it]=lfade;
  225. } /*End limits*/
  226.  
  227. int rnd(int low,int high) /*Returns a value between low and high (inclusive)*/
  228. {
  229.     return low+(((long)rand()*(high-low+1))>>15);
  230. } /*End rnd*/
  231.  
  232. int setscreen(int n) /* Set screen mode n.  Function value returns the mode
  233.   actually set.*/
  234. {
  235.     char far *bptr;
  236.     static int i;
  237.     if (n==-7)
  238.     {
  239.     /* Set up Hercules graphics mode.  Method as given in Programmer's
  240.     guide to PC & PS/2 Video Systems, Richard Wilton, Microsoft Press.*/
  241.  
  242.     bptr=(char far *) 0x00400049; /* BIOS data area*/
  243.     bptr[0]=7; /* Crt mode*/
  244.     bptr[1]=0x80;  bptr[2]=0x00;  /* Crt cols*/
  245.     bptr[3]=0x00;  bptr[4]=0x80;  /* Crt len*/
  246.     bptr[5]=0x00;  bptr[6]=0x00;  /* Crt start*/
  247.     bptr[7]=0x00;  bptr[8]=0x00;  /* Cursor posn*/
  248.     bptr[9]=0x00;  bptr[10]=0x00; /* Cursor posn*/
  249.     bptr[11]=0x00; bptr[12]=0x00; /* Cursor posn*/
  250.     bptr[13]=0x00; bptr[14]=0x00; /* Cursor posn*/
  251.     bptr[15]=0x00; bptr[16]=0x00; /* Cursor mode*/
  252.     bptr[17]=0x00; bptr[18]=0x00; /* Active page*/
  253.     bptr[19]=0xb4; bptr[20]=0x03; /* Addr 6845*/
  254.     bptr[21]=0x0a; /* Crt mode set (value for port 0x3b8*/
  255.     bptr[22]=0x00; /*Crt palette (unused)*/
  256.  
  257.     outp(0x3bf,1); /* Allow graphics mode*/
  258.     outp(0x3b8,0); /* Blank screen while programming CRTC*/
  259.     outpw(0x3b4,0x3500); /* Horizontal Total: 54 characters*/
  260.     outpw(0x3b4,0x2d01); /* Horizontal Displayed: 45 characters*/
  261.     outpw(0x3b4,0x2e02); /* Horizontal Synch Position: at 46th character*/
  262.     outpw(0x3b4,0x0703); /* Horizontal Synch Width: 7 character clocks*/
  263.     outpw(0x3b4,0x5b04); /* Vertical Total: 92 Characters (368 lines)*/
  264.     outpw(0x3b4,0x0205); /* Vertical Adjust: 2 scan lines*/
  265.     outpw(0x3b4,0x5706); /* Vertical Displayed: 87 character rows*/
  266.     outpw(0x3b4,0x5707); /* Vertical Synch Position: after 87th char row*/
  267.     outpw(0x3b4,0x0309); /* Max Scan Line: 4 scan lines per character*/
  268.     /* Clear screen before re-enabling*/
  269.     bptr=(char far *) 0xb0000000;
  270.     for (i=0;i<0x8000;i++) bptr[i]=0;
  271.     outpw(0x3b8,0x0a); /* Enable graphics mode and video*/
  272.     return -7;
  273.     }
  274.     else
  275.     {
  276.     inr.h.ah=0;
  277.     inr.h.al=n;
  278.     int86(0x10,&inr,&outr); /* Set screen mode*/
  279.     inr.h.ah=15;
  280.     int86(0x10,&inr,&outr); /* Get video state*/
  281.     return outr.h.al;
  282.     }
  283. } /*End setscreen*/
  284.  
  285. void setup_ega() /* Set up the ega screen for fireworks graphics*/
  286. {
  287.     if (mode==EGM)
  288.     {
  289.     outp(0x3ce,3);
  290.     outp(0x3cf,0x18);/*Select Xor operation*/
  291.     }
  292. } /*End setup_ega*/
  293.  
  294. void reset_ega() /* Reset ega screen to standard settings for graphics*/
  295. {
  296.     if (mode==EGM)
  297.     {
  298.     outp(0x3ce,3);
  299.     outp(0x3cf,0);/*Cancel Xor*/
  300.     outp(0x3ce,8);
  301.     outp(0x3cf,0xff);/*No mask*/
  302.     outp(0x3c4,2);
  303.     outp(0x3c5,0xff);/*Enable all bit planes*/
  304.     }
  305. } /*End reset_ega*/
  306.  
  307. void save_background() /* Save the current screen background into restore_screen*/
  308. {
  309.     if (mode==TXTM)
  310.     {
  311.         for(address=0;address<4000;address++)
  312.     {
  313.         restore_screen[address]=txtpointer[address];
  314.         }
  315.     }
  316. } /*End save_background*/
  317.  
  318. void clearscreen() /* Clear the screen*/
  319. {
  320.     switch(mode)
  321.     {
  322.     case EGM:
  323.         reset_ega();
  324.     for (address=0;address<28000;address++)
  325.     {
  326.             egapointer[address]=0;
  327.     }
  328.         break;
  329.     case CGM:
  330.         for (address=0;address<8000;address++)
  331.         {
  332.             cgapointer0[address]=0;
  333.             cgapointer1[address]=0;
  334.         }
  335.         break;
  336.     case TXTM:
  337.         for(address=0;address<4000;address++)
  338.         {
  339.             txtpointer[address]=0;
  340.         }
  341.         save_background();
  342.         break;
  343.     case HGCM:
  344.     for (address=0;address<7830;address++)
  345.     {
  346.         hgcpointers[0][address]=0;
  347.         hgcpointers[1][address]=0;
  348.         hgcpointers[2][address]=0;
  349.         hgcpointers[3][address]=0;
  350.     }
  351.     break;
  352.     }
  353. } /*End clearscreen*/
  354.  
  355. void swap_cga() /* Swaps to the other palette (only if in cga mode)*/
  356. {
  357.     if (mode==CGM)
  358.     {
  359.         cga_palette=1-cga_palette;
  360.         inr.h.ah=11;
  361.         inr.h.bh=1;
  362.         inr.h.bl=cga_palette;
  363.         int86(0x10,&inr,&outr);
  364.     }
  365. } /*End cga_palette*/
  366.  
  367. void showega(int x,int y,int col,int size,int on)
  368. /*EGA - Show (or remove) point x,y if it is in the screen area*/
  369. {
  370.     static int i,x1,x2,dummy,lbit,rbit,xsh,sizem1,sizem1mi,rowaddr;
  371.     if (y>=ymin) if (x>=xmin) if (x<=xmax)
  372.     {
  373.         xsh=x>>sh;
  374.         sizem1=size-1;
  375.         for (i=-sizem1; i<=sizem1; i++)
  376.         {
  377.             sizem1mi=sizem1-abs(i);
  378.             rowaddr=rowaddress[(y>>sh)+i];
  379.             x1=xsh-sizem1mi;
  380.             x2=xsh+sizem1mi;
  381.             while (x1<=x2)
  382.             {
  383.                 lbit=x1 & 7;
  384.                 rbit=(x2>=(x1 | 7))? 7 : lbit+x2-x1;
  385.             outp(0x3ce,8);
  386.         outp(0x3cf,(unsigned char)(0xff<<(7-rbit+lbit))>>lbit);/*Set mask*/
  387.                 dummy=egapointer[address=rowaddr+(x1>>3)];/*Load latches*/
  388.                 outp(0x3c4,2);
  389.                 outp(0x3c5,col);/*Select bit planes*/
  390.                 egapointer[address]=0xff;/*Set selected bits to 1*/
  391.                 x1=x1+rbit-lbit+1;
  392.             }
  393.         }
  394.     }
  395. } /*End showega*/
  396.  
  397. void showcga(int x,int y,int col,int size,int on)
  398. /*CGA - Show (or remove) point x,y if it is in the screen area*/
  399. {
  400.     static int shift[4]={6,4,2,0},i,j,sx,sy,pair,xsh,ysh,sizem1,sizem1mi,rowaddr;
  401.     if (y>=ymin) if (x>=xmin) if (x<=xmax)
  402.     {
  403.         xsh=x>>sh;
  404.         ysh=y>>sh;
  405.         sizem1=size-1;
  406.         for (i=-sizem1; i<=sizem1; i++)
  407.         {
  408.             sizem1mi=sizem1-abs(i);
  409.             sy=ysh+i;
  410.             rowaddr=rowaddress[sy];
  411.             cgapointer=(sy & 1)? cgapointer1 : cgapointer0;
  412.             for (j=-sizem1mi; j<=sizem1mi; j++)
  413.             {
  414.                 sx=xsh+j;
  415.                 address=rowaddr+sx>>2;
  416.                 pair=sx & 3;
  417.         cgapointer[address]^=((col & 3)<<shift[pair]);
  418.             }
  419.         }
  420.     }
  421. } /*End showcga*/
  422.  
  423. void showhgc(int x,int y,int col,int size,int on)
  424. /*Hercules - Show (or remove) point x,y if it is in the screen area*/
  425.  
  426. {
  427.     static int i,j,sx,sy,xsh,ysh,sizem1,sizem1mi,rowaddr;
  428.     if (y>=ymin) if (x>=xmin) if (x<=xmax)
  429.     {
  430.     xsh=x>>sh;
  431.     ysh=y>>sh;
  432.     sizem1=size-1;
  433.     for (i=-sizem1; i<=sizem1; i++)
  434.     {
  435.         sizem1mi=sizem1-abs(i);
  436.         sy=ysh+i;
  437.         rowaddr=rowaddress[sy];
  438.         hgcpointer=hgcpointers[sy & 3];
  439.         for (j=-sizem1mi; j<=sizem1mi; j++)
  440.         {
  441.         sx=xsh+j;
  442.         address=rowaddr+(sx>>3);
  443.         hgcpointer[address]^=(1<<(7-(sx & 7)));
  444.         }
  445.     }
  446.     }
  447. } /*End showhgc*/
  448.  
  449. void showtxt(int x,int y,int col,int size,int on)
  450. /*Text - Show (or remove) point x,y if it is in the screen area*/
  451. {
  452.     if (y>=ymin) if (x>=xmin) if (x<=xmax)
  453.     {
  454.         address=(rowaddress[y>>shy]+(x>>shx))<<1;
  455.         if (on)
  456.         {
  457.             txtpointer[address]=cpoint[size];
  458.             txtpointer[address+1]=col;
  459.         }
  460.         else
  461.         {
  462.             txtpointer[address]=restore_screen[address];
  463.             txtpointer[address+1]=restore_screen[address+1];
  464.         }
  465.     }
  466. } /*End showtxt*/
  467.  
  468. void create(int it,int *pt,int *plist,int *num_inlist) /*Create a point for
  469.   item it, add to list plist, increment count num_inlist*/
  470. {
  471.     static int vel,angle;
  472.     if (pfree>=0)
  473.         *pt=pfree;
  474.     else
  475.     {
  476.         reset_ega();
  477.         printf("Error: point data storage overflow");
  478.         exit(0);
  479.     }
  480.     itemno[*pt]=it;
  481.     g[*pt]=gv;
  482.     fade[*pt]=fadev[it];
  483.     state[*pt]=0;
  484.     x[*pt]=rnd(xl[it],xh[it]);
  485.     y[*pt]=rnd(yl[it],yh[it]);
  486.     vel=rnd(vell[it],velh[it]);
  487.     angle=rnd(angl[it],angh[it]);
  488.     xvel[*pt]=vel*sina[180+angle];
  489.     yvel[*pt]=-(vel*cosa[180+angle]);
  490.     col[*pt]=col_table[rnd(coll[it],colh[it])];
  491.     size[*pt]=sizev[it];
  492.     alive[*pt]=rnd(alivel[it],aliveh[it]);
  493. /* Remove from free list and add to indicated list*/
  494.     pfree=next[*pt];
  495.     next[*pt]=*plist;
  496.     *plist=*pt;
  497.     (*num_inlist)++;
  498. } /*End create*/
  499.  
  500. void move_points() /*Move all active points through 1 step*/
  501. {
  502.     static int i,j,k,n,lastj,nextj;
  503. /* The motion is smoothed by distributing most of the necessary time wasting
  504. in a delay loop that is executed slow1 times each time a point is moved.  This
  505. is also important for generating the best sound effects.  A number of
  506. parameters enter into the calculation of slow1 and these are specified in terms
  507. of a unit that represents the time required to execute the delay loop once.
  508. Only a reasonable estimate of the delay is needed because the delay loop will
  509. short-circuit itself if the next timer tick occurs before all points have been
  510. moved, and on the other hand any excess time is soaked up by the tick synch
  511. routine.
  512. Parameters:  tot_loop  - time taken for one timer tick
  513.              indep     - part of execution time that is independent of num_active
  514.              per_point - extra execution time per point*/
  515.     if (num_active>0)
  516.     {
  517.         slow1=(tot_loop-indep-num_active*per_point)/num_active;
  518.         j=pactive;
  519.         lastj=-1;
  520.         n=num_active;
  521.         for(k=1;k<=n;k++)
  522.         {
  523.             nextj=next[j];
  524.         if (noise>0) if (rand()<noise) outp(0x61,inp(0x61)|3);
  525.             if (state[j]>0) show(x[j],y[j],col[j],size[j],0);
  526.             else state[j]=state2;
  527.             yvel[j]+=g[j];
  528.             x[j]+=xvel[j];
  529.             if ((y[j]+=yvel[j])>ymax) /* Don't allow to fall off the bottom*/
  530.             {
  531.                 y[j]-=yvel[j];
  532.                 xvel[j]=0;
  533.             }
  534.             if (--alive[j]<=0)
  535.             {
  536.                 if (size[j]>1) /* Fade point*/
  537.                 {
  538.                     size[j]--;
  539.                     alive[j]=fade[j];
  540.                     show(x[j],y[j],col[j],size[j],1);
  541.                 }
  542.                 else /* Remove point*/
  543.                 {
  544.                     if (lastj==-1) pactive=next[j];
  545.                     else next[lastj]=next[j];
  546.                     next[j]=pfree;
  547.                     pfree=j;
  548.                     j=lastj;
  549.                     num_active--;
  550.                 }
  551.             }
  552.             else
  553.                 show(x[j],y[j],col[j],size[j],1);
  554.         if (noise>0) outp(0x61,inp(0x61)&0xfc);
  555.             for (i=1;i<=slow1;i++) /* Delay loop*/
  556.             {
  557.                 ticks2=get_ticks();
  558.                 if (ticks1!=ticks2) slow1=0; /* Enough delay already*/
  559.             }
  560.             lastj=j;
  561.             j=nextj;
  562.         }
  563.     }
  564.     if ((noise=abs(noise))>0) noise-=300;
  565. /* Swap cga palette any time the screen goes quiet*/
  566.     if (num_active<=swaplevel)
  567.     {
  568.         if (swap_flag)
  569.         {
  570.             swap_cga();
  571.             swap_flag=0;
  572.         }
  573.     }
  574.     else
  575.         swap_flag=1;
  576.     count++;
  577. /* Speed synchronization on timer tick*/
  578.     if (synch)
  579.     {
  580.         while (ticks1==ticks2) ticks2=get_ticks();
  581.         ticks1=ticks2;
  582.     }
  583. } /*End move_points*/
  584.  
  585. void activate(int it) /*Activate all dormant points for item it*/
  586. {
  587.     static int j,n;
  588. /* Insert into list of active points*/
  589.         j=pdormant[it];
  590.         n=1;
  591.         while (next[j]>-1)
  592.         {
  593.             j=next[j];
  594.             n++;
  595.             if (n>np)
  596.             {
  597.                 reset_ega();
  598.                 printf("Error: list structure corrupt");
  599.                 exit(0);
  600.             }
  601.         }
  602.         next[j]=pactive;
  603.         pactive=pdormant[it];
  604.         num_active+=n;
  605.         num_dormant-=n;
  606.         pdormant[it]=-1;
  607. } /*End activate*/
  608.  
  609. void process(int t,int waiting) /*Process currently set devices for t intervals*/
  610. {
  611.     static int it,i,timer;
  612.     for (timer=1;timer<=t;timer++)
  613.     {
  614.         for (it=0;it<NI;it++)
  615.         {
  616.             if (item_alive[it]>0) item_alive[it]--;
  617.             else devicetype[it]=0;
  618.             switch(devicetype[it])
  619.             {
  620.             /*SPURT*/ case 1:   if (wait[it]>130) create(it,&newpt,&pactive,&num_active);
  621.                 else if (wait[it]==0)
  622.                 {
  623.                     setrange(&coll[it],&colh[it],rnd(mincol,maxcol),rnd(mincol,maxcol));
  624.                     wait[it]=np+130;
  625.                 }
  626.                 break;
  627.             /*FLARE*/ case 2:   if (wait[it]&fl_mask) create(it,&newpt,&pactive,&num_active);
  628.                 if (wait[it]==0)
  629.                 {
  630.                     if (++coll[it]>=maxcol) coll[it]=mincol;
  631.                     colh[it]=coll[it]+1;
  632.                     wait[it]=50;
  633.                 }
  634.                 break;
  635.             /*BURST*/ case 3:   if (wait[it]>burstwait) create(it,&master[it],&pdormant[it],&num_dormant);
  636.                 else if (wait[it]==0)
  637.                 {
  638.                     activate(it);
  639.                     if (quiet==0) noise=-3000;
  640.                 }
  641.                 break;
  642.             /*ROCKET*/ case 4:  if (wait[it]==0)
  643.                 {
  644.                     activate(it);
  645.                     item_alive[it]=alive[master[it]]+fade[master[it]]*(size[master[it]]-1);
  646.                 }
  647.                 else if (wait[it]<0)
  648.                 {
  649.                     create(it,&newpt,&pactive,&num_active);
  650.                     x[newpt]=x[master[it]]+rnd(-64,64);
  651.                     y[newpt]=y[master[it]]+rnd(-64,64);
  652.                 }
  653.                 break;
  654.             /*ROMAN*/ case 5:   if ((wait[it]<=9) && (wait[it]>0))
  655.                 {
  656.                     create(it,&newpt,&pdormant[it],&num_dormant);
  657.                     x[newpt]=x[master[it]]+ro_rad*sina[180+(360*(wait[it]-5)/9)];
  658.                     y[newpt]=y[master[it]]-ro_rad*cosa[180+(360*(wait[it]-5)/9)];
  659.                     xvel[newpt]=xvel[master[it]];
  660.                     yvel[newpt]=yvel[master[it]];
  661.                     alive[newpt]=alive[master[it]];
  662.                     col[newpt]=col[master[it]];
  663.                 } else if (wait[it]==0) {
  664.                     limits(it,0,0,0,0,0,0,0,0,5,10,col[master[it]],col[master[it]],1,0);
  665.                     activate(it);
  666.                     item_alive[it]=alive[master[it]]+fade[master[it]]*(size[master[it]]-1);
  667.                 }
  668.                 else if (wait[it]<0)
  669.                 {
  670.                     create(it,&newpt,&pactive,&num_active);
  671.                     x[newpt]=x[master[it]]+rnd(-256,256);
  672.                     y[newpt]=y[master[it]]+rnd(-64,64);
  673.                 }
  674.                 break;
  675.             /*WHEEL*/ case 6:    for(i=1;i<=wheelrep[it];i++)
  676.                 {
  677.                     angl[it]+=wheelstep[it];
  678.                     angh[it]+=wheelstep[it];
  679.                     if (angl[it]>=180)
  680.                     {
  681.                         angl[it]-=360;
  682.                         angh[it]-=360;
  683.                         if ((wheelstep[it]+=2)>wheelsteplim) wheelstep[it]=wheelsteplim;
  684.                         if (++wheelrep[it]>wheelreplim) wheelrep[it]=wheelreplim;
  685.                     }
  686.                     xl[it]=xref[it]+wheelradius*cosa[180+angl[it]];
  687.                     xh[it]=xl[it];
  688.                     yl[it]=yref[it]+wheelradius*sina[180+angl[it]];
  689.                     yh[it]=yl[it];
  690.                     if (i&wh_mask) create(it,&newpt,&pactive,&num_active);
  691.                 }
  692.                 break;
  693.             } /*End switch*/
  694.             if ((wait[it]>-1) && (it!=waiting)) wait[it]--;
  695.         }
  696.         if (kbhit()) terminate();
  697.         move_points();
  698.     }
  699. } /*End process*/
  700.  
  701. void opening_screen() /*Display opening screen*/
  702. {
  703.     static int i,j,k,l,kk,npoints,moving,xp[150],yp[150],tlength,xoff,yoff,
  704.         lastj,nextj;
  705.     static char txt[]="PYRO";
  706.     tlength=strlen(txt);
  707.     xoff=(sc_xmax-tlength*2*etx_f1+4*etx_f2)/2;
  708.     yoff=sc_ymax/3;
  709.     gv=2;
  710.     state2=1;
  711.     swaplevel=-1;
  712.     clearscreen();
  713.     if (mode==CGM) put_string(c2,col_table[mincol],9,19);
  714.     else put_string(c2,col_table[mincol],29,19);
  715.     if (mode==CGM) put_string(c3,col_table[mincol],9,21);
  716.     else put_string(c3,col_table[mincol],29,21);
  717.     save_background();
  718.     setup_ega();
  719.     /* Store the point positions*/
  720.     npoints=-1;
  721.     moving=0;
  722.     bytepointer=(char far *)0xf0000000;
  723.     for (i=0;i<=tlength;i++)
  724.     {
  725.         if (txt[i]!=' ')
  726.             for (j=7;j>=0;j--)
  727.                 for (k=0;k<=7;k++)
  728.                 {
  729.                     if ((bytepointer[0xfa6e+j+8*txt[i]] & (0x80>>k))>0)
  730.                     {
  731.                         npoints++;
  732.                         xp[npoints]=(xoff+2*etx_f1*i+2*etx_f2*k)<<sh;
  733.                         yp[npoints]=(yoff+oty_fac*j)<<sh;
  734.                     }
  735.                 }
  736.     }
  737.     /* Generate the points in random order*/
  738.     kk=1;
  739.     if (script==SIMPLE) kk=3;
  740.     k=0;
  741.     while (npoints>-1 || moving>0)
  742.     {
  743.         if (npoints>-1 && k==0)
  744.         {
  745.             i=rnd(0,npoints);
  746.             limits(0,sc_xmax/2,sc_xmax/2,baseline,baseline,
  747.               0,0,0,0,120,170,mincol,maxcol,2,0);
  748.             create(0,&newpt,&pactive,&num_active);
  749.             l=alive[newpt]-1;
  750.             xvel[newpt]=(xp[i]-x[newpt])/l;
  751.         x[newpt]=xp[i]-xvel[newpt]*l;
  752.             yvel[newpt]=-(gv*l)/2+(yp[i]-y[newpt])/l;
  753.             y[newpt]=(long)yp[i]-((long)yvel[newpt]*(long)l+(long)gv*(long)l*(long)l/2);
  754.             moving++;
  755.             xp[i]=xp[npoints];
  756.             yp[i]=yp[npoints];
  757.             npoints--;
  758.         }
  759.     process(1,-1);
  760.     setup_ega(); /* Quick C seems to need this here*/
  761.         j=pactive;
  762.         lastj=-1;
  763.         while (j>-1) /* Stop each point at its destination, pre-empting move_points*/
  764.         {
  765.             nextj=next[j];
  766.             if (alive[j]<=1)
  767.             {
  768.                 show(x[j],y[j],col[j],size[j],0);
  769.                 show(x[j],y[j],col[j],ot_size,1);
  770.                 if (mode==TXTM)
  771.                 {
  772.                     restore_screen[address]=txtpointer[address];
  773.                     restore_screen[address+1]=txtpointer[address+1];
  774.                 }
  775.                 if (lastj==-1) pactive=next[j];
  776.                 else next[lastj]=next[j];
  777.                 next[j]=pfree;
  778.                 pfree=j;
  779.                 j=lastj;
  780.                 num_active--;
  781.                 moving--;
  782.             }
  783.             lastj=j;
  784.             j=nextj;
  785.         }
  786.         k++;
  787.         if (k>kk) k=0;
  788.     }
  789.     for (i=1;i<=4*18;i++) /* Pause with title on screen*/
  790.     {
  791.         while (ticks1==ticks2) ticks2=get_ticks();
  792.         ticks1=ticks2;
  793.     }
  794.     clearscreen();
  795.     setup_ega();
  796.     gv=2;
  797.     swaplevel=10;
  798. } /*End opening_screen*/
  799.  
  800. void terminate() /*Terminate display*/
  801. {
  802.     static int i,j,k,l;
  803.     if ((inkey=kbhit()? getch(): 0)!=27)
  804.         for (j=1;(j<=800) && (num_active+num_dormant>0);j++) process(1,-1);
  805.     inr.h.ah=0x2c;
  806.     int86(0x21,&inr,&outr); /* Get end time*/
  807.     he=outr.h.ch;
  808.     me=outr.h.cl;
  809.     se=outr.h.dh;
  810.     excount=count;
  811.     if (inkey!=27 && capacity==0)
  812.     {
  813.         gv=0;
  814.         state2=1;
  815.         bytepointer=(char far *)0xf0000000;
  816.         clearscreen();
  817.         setup_ega();
  818.         for (i=0;i<=6;i++)
  819.         {
  820.             if (txt[i]!=' ')
  821.                 for (j=7;j>=0;j--)
  822.                     for (k=0;k<=7;k++)
  823.                         if ((bytepointer[0xfa6e+j+8*txt[i]] & (0x80>>k))>0)
  824.                         {
  825.                             limits(0,etx_off+etx_f1*i+etx_f2*k+tr_l,etx_off+etx_f1*i+etx_f2*k+tr_h,ety_off+ety_fac*j+tr_l,ety_off+ety_fac*j+tr_h,0,0,0,0,30,50,endcol,endcol,t_s,t_f);
  826.                             create(0,&newpt,&pactive,&num_active);
  827.                             for (l=1;l<=3000;l++);
  828.                         }
  829.                         process(4,-1);
  830.         }
  831.         for (i=1;(i<=800) && (num_active>0);i++)
  832.         {
  833.             process(1,-1);
  834.             j=pactive;
  835.             while (j>-1) /* Make titles start to fall*/
  836.             {
  837.                 if (alive[j]<=10) g[j]=1;
  838.                 j=next[j];
  839.             }
  840.         }
  841.     }
  842.     clearscreen();
  843.     setscreen(3);
  844.     if (inkey==0)
  845.     {
  846.         if (he<hs) he=he+24;
  847.         stime=60*ms+ss;
  848.         etime=60*me+se;
  849.         etime=etime+3600*(he-hs);
  850.         extime=etime-stime;
  851.         printf("Ideal  execution time: %d seconds\n",(int)(excount/18.2));
  852.         printf("Actual execution time: %d seconds\n",extime);
  853.     printf("Ratio: %f\n",extime/(excount/18.2));
  854.     }
  855.     printf("\n\n\nPYRO was brought to you by\n\n\n\n");
  856.     printf("                           Dimension 88,\n");
  857.     printf("                           P.O. Box 202,\n");
  858.     printf("                           Mt Ommaney,\n");
  859.     printf("                           Queensland  4074.\n");
  860.     printf("                           (07) 376 8383\n");
  861.     printf("\n\n\nPYRO (c) 1988  K.G. Shields.");
  862.     printf("\n     (c) 1987  K.G. Shields.\n");
  863. #if MSC
  864.     printf("\nCompiled using Microsoft Optimising C Compiler\n");
  865. #elif QUICKC
  866.     printf("\nCompiled using Microsoft QuickC\n");
  867. #elif TURBOC
  868.     printf("\nCompiled using Turbo C\n");
  869. #endif
  870.     exit(0);
  871. } /*End terminate*/
  872.  
  873. void calc_end() /*Calculate endpoint for burst*/
  874. {
  875.     endpt=np-wait[ci]+burstwait+1;
  876.     if ((mastercol=col[master[ci]])==maxcol) mastercol=maxcol-1;
  877.     alive[master[ci]]=endpt-(size[master[ci]]-1)*fade[master[ci]];
  878.     xend=x[master[ci]]+endpt*xvel[master[ci]];
  879.     yend=y[master[ci]]+endpt*yvel[master[ci]]+(gv*endpt*endpt)/2;
  880. } /*End calc_end*/
  881.  
  882. void startup(int devtype,int xi,int yi,int life,int p1,int p2,int p3,int p4,int waiting) /*Initializes a device*/
  883. {
  884.     ci=0;
  885.     while (item_alive[ci]>0)
  886.     {
  887.         process(1,waiting);
  888.         if (++ci>=NI) ci=0;
  889.     }
  890.     devicetype[ci]=devtype;
  891.     item_alive[ci]=life;
  892.     switch(devicetype[ci])
  893.     {
  894.     /*SPURT*/ case 1:   limits(ci,xi-spread,xi+spread,baseline,baseline,sp_vl,sp_vh,-20,20,120,160,rnd(mincol,maxcol),rnd(mincol,maxcol),2,25);
  895.         wait[ci]=np+130;
  896.         break;
  897.     /*FLARE*/ case 2:   coll[ci]=rnd(mincol,maxcol-1);
  898.         limits(ci,xi-spread,xi+spread,baseline,baseline,fl_vl,fl_vh,-17,17,20,30,coll[ci],coll[ci]+1,2,2);
  899.         wait[ci]=50;
  900.         break;
  901.     /*BURST*/ case 3:   if (waiting<0) coll[ci]=rnd(mincol,maxcol-1);
  902.         else coll[ci]=mastercol;
  903.         limits(ci,xi-spread,xi+spread,yi-spread,yi+spread,rnd(p1,p2),rnd(p3,p4),-180,180,burstlife,2*burstlife,coll[ci],coll[ci]+1,2,rnd(burstlife,3*burstlife));
  904.         wait[ci]=np+burstwait;
  905.         break;
  906.     /*ROCKET*/ case 4:  limits(ci,xi,xi,baseline,baseline,rk_vl,rk_vh,p1,p2,100,100,mincol,maxcol,rnd(3,4),3);
  907.         wait[ci]=20;
  908.         create(ci,&master[ci],&pdormant[ci],&num_dormant);
  909.         limits(ci,xi,xi,baseline,baseline,rktail_vl,rktail_vh,90,90,6,7,col[master[ci]],col[master[ci]],2,20);
  910.         vell[ci]=vell[ci]>>1;
  911.         velh[ci]=velh[ci]>>1;
  912.         calc_end();
  913.         break;
  914.     /*ROMAN*/ case 5:   limits(ci,xi,xi,baseline,baseline,ro_vl,ro_vh,-10,10,100,100,mincol,maxcol,3,1);
  915.         wait[ci]=30;
  916.         create(ci,&master[ci],&pdormant[ci],&num_dormant);
  917.         calc_end();
  918.         break;
  919.     /*WHEEL*/ case 6:   coll[ci]=rnd(mincol,maxcol-1);
  920.         limits(ci,xi,xi,yi,yi,wh_vl,wh_vh,-1,1,15,20,coll[ci],coll[ci]+1,2,2);
  921.         xref[ci]=xl[ci];
  922.         yref[ci]=yl[ci];
  923.         wheelstep[ci]=wheelstepv;
  924.         wheelrep[ci]=1;
  925.         wait[ci]=0;
  926.         break;
  927.     }
  928. } /*End startup*/
  929.  
  930. void wait_for(int waitlevel) /* Waits until there are waitlevel or fewer points
  931.   on the screen*/
  932. {
  933.     while (num_active>waitlevel) process(1,-1);
  934. } /*End wait_quiet*/
  935.  
  936. void multiple(int typ,int n,int rep,int life,int gap,int pause,int waitlevel)
  937.   /* Multiple item display*/
  938. {
  939.     static int i,j;
  940.     for (j=1;j<=rep;j++)
  941.     {
  942.         for (i=1;i<=n;i++)
  943.         {
  944.             switch(typ)
  945.             {
  946.             /*ROCKET*/ case 4: startup(rocket,sc_xmax/4+i*(sc_xmax/(n+1))/2,baseline,100,-45,45,0,0,-1);
  947.                 if (rand()<25000) startup(burst,xend>>sh,yend>>sh,100,1,3,5,12,ci);
  948.                 break;
  949.             /*ROMAN*/ case 5: startup(roman,i*(sc_xmax/(n+1)),baseline,100,0,0,0,0,-1);
  950.                 startup(burst,xend>>sh,yend>>sh,100,8,8,10,12,ci);
  951.                 break;
  952.             default: if (typ==burst) startup(burst,rnd(sc_xmax/4,3*sc_xmax/4),rnd(sc_ymax/7,4*sc_ymax/7),life,1,3,5,12,-1);
  953.                 else if (typ==wheel) startup(typ,i*(sc_xmax/(n+1)),2*sc_ymax/3,life,0,0,0,0,-1);
  954.                 else startup(typ,i*(sc_xmax/(n+1)),baseline,life,0,0,0,0,-1);
  955.             } /*End switch*/
  956.             process(gap,-1);
  957.         }
  958.         process(pause,-1);
  959. /* Create gaps to allow cga colour changes*/
  960.         if (mode==CGM) wait_for(waitlevel);
  961.     }
  962. }/*End multiple*/
  963.  
  964. void test_capacity() /* Test the point capacity of the current processor*/
  965. /* This function is used for timing tests.  The program should be run with
  966. all slowdown features turned off when this is invoked.*/
  967. {
  968.     static int n;
  969.     inr.h.ah=0x2c;
  970.     int86(0x21,&inr,&outr); /* Get start time*/
  971.     hs=outr.h.ch;
  972.     ms=outr.h.cl;
  973.     ss=outr.h.dh;
  974.     np=tot_loop/3;
  975.     n=tot_loop/30;
  976.     if (n>6) n=6;
  977.     multiple(spurt,n,1,np,0,0,10000);
  978.     while (num_active>0)
  979.     {
  980.         /* Wait for a timer tick*/
  981.         ticks1=get_ticks();
  982.         ticks2=ticks1;
  983.         while (ticks1==ticks2) ticks2=get_ticks();
  984.         ticks1=ticks2;
  985.         /* Move points then see if it happened within 1 tick*/
  986.         process(1,-1);
  987.         if (ticks2==ticks1 && num_active>capacity) capacity=num_active;
  988.         if (num_active>TP+n)
  989.         {
  990.             capacity=TP;
  991.             num_active=0;
  992.         }
  993.     }
  994.     clearscreen();
  995.     setscreen(3);
  996.     printf("Capacity %d points at full speed",capacity);
  997. }/*End test_capacity*/
  998.  
  999. main(int argc,char **argv)
  1000. {
  1001.     static int ega_byte,val1,val2;
  1002.     static unsigned int count;
  1003.     report=0; /* If non-zero, prints debugging information*/
  1004.     quiet=0; /* If non-zero, suppresses sound effects*/
  1005.     adapter=UNKNOWN;
  1006.     screen=UNKNOWN;
  1007.     mode=UNKNOWN;
  1008. /* Decode any command line parameters*/
  1009.     continuous=0;
  1010.     fullspeed=0;
  1011.     testcapacity=0;
  1012.     for (im=1; im<argc; im++)
  1013.     {
  1014.         if ((strlen(argv[im])==1) && ((argv[im][0]=='c') || (argv[im][0]=='C'))) continuous=1;
  1015.         if ((strlen(argv[im])==1) && ((argv[im][0]=='r') || (argv[im][0]=='R'))) report=1;
  1016.         if ((strlen(argv[im])==1) && ((argv[im][0]=='q') || (argv[im][0]=='Q'))) quiet=1;
  1017.         if ((strlen(argv[im])==1) && ((argv[im][0]=='f') || (argv[im][0]=='F'))) fullspeed=1;
  1018.         if ((strlen(argv[im])==1) && ((argv[im][0]=='t') || (argv[im][0]=='T'))) testcapacity=1;
  1019.         if ((strlen(argv[im])>1) && ((argv[im][0]=='e') || (argv[im][0]=='E'))) mode=EGM;
  1020.         if ((strlen(argv[im])>1) && ((argv[im][0]=='c') || (argv[im][0]=='C'))) mode=CGM;
  1021.         if ((strlen(argv[im])>1) && ((argv[im][0]=='t') || (argv[im][0]=='T'))) mode=TXTM;
  1022.     if ((strlen(argv[im])>1) && ((argv[im][0]=='h') || (argv[im][0]=='H'))) mode=HGCM;
  1023.     }
  1024. /* Identify the display adapter and screen*/
  1025.     /* Check for VGA*/
  1026.     inr.h.ah=0x1a;
  1027.     inr.h.al=0;
  1028.     int86(0x10,&inr,&outr);
  1029.     if (outr.h.al!=0)
  1030.     {
  1031.         /* VGA present, test whether active, get screen type*/
  1032.         if (outr.h.bl==7)
  1033.         {
  1034.             adapter=VGA;
  1035.             screen=MONO;
  1036.         }
  1037.         else if(outr.h.bl==8)
  1038.         {
  1039.             adapter=VGA;
  1040.             screen=COLOUR;
  1041.         }
  1042.     }
  1043.     if (adapter==UNKNOWN)
  1044.     /* Check for EGA*/
  1045.     {
  1046.         inr.h.ah=0x12;
  1047.         inr.h.bl=0x10;
  1048.         int86(0x10,&inr,&outr);
  1049.         if (outr.h.bl!=0x10)
  1050.         {
  1051.             /* EGA present, test whether active, get screen type*/
  1052.             bytepointer=(char far *)0x400087;
  1053.             ega_byte=*bytepointer;
  1054.             if ((ega_byte & 8)==0)
  1055.             {
  1056.                 adapter=EGA;
  1057.                 if (outr.h.bh==0) screen=COLOUR;
  1058.                 else screen=MONO;
  1059.             }
  1060.         }
  1061.     }
  1062.     if (adapter==UNKNOWN)
  1063.     /* Check for CGA*/
  1064.     {
  1065.         wordpointer=(unsigned int far *)0x400063;
  1066.         address_6845=*wordpointer;
  1067.         if ((address_6845 & 0x40)!=0)
  1068.         {
  1069.             adapter=CGA;
  1070.             screen=COLOUR;
  1071.         }
  1072.         else
  1073.     {
  1074.         adapter=MDA;
  1075.         screen=MONO;
  1076.         /* Check for HGC by looking for a change in bit 7 of port 0x3ba*/
  1077.         val1=inp(0x3ba) & 0x80;
  1078.         for (count=0;count<32767;count++)
  1079.         {
  1080.         val2=inp(0x3ba) & 0x80;
  1081.         if (val2!=val1)
  1082.         {
  1083.             adapter=HGC;
  1084.             count=32767;
  1085.         }
  1086.         }
  1087.         }
  1088.     }
  1089.     if (report) printf("Detected %s adapter\n",ddesc[adapter]);
  1090.     if (report && ((adapter==VGA) || (adapter==EGA))) printf("Detected %s screen\n",sdesc[screen]);
  1091. /* Determine speed of machine*/
  1092. /* Wait for a tick*/
  1093.     ticks2=get_ticks();
  1094.     do
  1095.         ticks1=get_ticks();
  1096.     while (ticks2==ticks1);
  1097. /* Count the number of calls to the next tick*/
  1098.     tot_loop=0;
  1099.     do
  1100.     {
  1101.         ticks2=get_ticks();
  1102.         tot_loop++;
  1103.     }
  1104.     while (ticks2==ticks1);
  1105.     tot_loop=tot_loop;
  1106.     /* Adjust reported value for various compilers and optimizations*/
  1107.     rep_tot_loop=tot_loop*REPCOR;
  1108.     if (report) printf("Measured processor speed: %d\n",rep_tot_loop);
  1109.     if (report) printf("For comparison: 4.77 MHz XT = 81, 8MHz AT = 330\n");
  1110.     tot_loop=tot_loop*CALCCOR; /* Adjust by a different factor for internal use*/
  1111.     if (adapter==MDA) est_capacity=.6*tot_loop;
  1112.     else est_capacity=.4*tot_loop;
  1113.     if (report) printf("\nCan move approx. %d points without loss of speed\n",est_capacity);
  1114.     np=est_capacity/2;
  1115.     if (np>60) np=60;
  1116.     if (np>=25) script=STANDARD;
  1117.     else
  1118.     {
  1119.         script=SIMPLE;
  1120.         np=1.5*np;
  1121.         if (report) printf("Using simplified script\n");
  1122.     }
  1123.     if (report) printf("Using a limit of %d points per device\n",np);
  1124. /* If not specified on the command line, decide which mode to use*/
  1125.     if (mode==UNKNOWN)
  1126.     {
  1127.         if ((adapter==VGA) || (adapter==EGA)) mode=EGM;
  1128.     else if (adapter==CGA) mode=CGM;
  1129.     else if (adapter==HGC) mode=HGCM;
  1130.         else mode=TXTM;
  1131.         if ((mode==EGM) && (tot_loop<250))
  1132.         {
  1133.             mode=CGM;
  1134.             if (report) printf("This computer is too slow to run the EGA mode display\n");
  1135.         }
  1136.         if (report) printf("Display mode set to %s\n",mdesc[mode]);
  1137.     }
  1138. /* Parameters that relate to the graphics screen being used*/
  1139.     if (mode==EGM)
  1140.     {
  1141.     sh=5;
  1142.         sc_xmax=639;
  1143.         sc_ymax=349;
  1144.         margin=5;
  1145.         baseline=340;
  1146.         spread=5;
  1147.         sp_vl=3;
  1148.         sp_vh=8;
  1149.         fl_vl=4;
  1150.         fl_vh=8;
  1151.         fl_mask=0xffff;
  1152.         rk_vl=5;
  1153.         rk_vh=10;
  1154.         rktail_vl=-2;
  1155.         rktail_vh=2;
  1156.         ro_vl=6;
  1157.         ro_vh=11;
  1158.         wh_vl=4;
  1159.         wh_vh=7;
  1160.         wheelradius=10<<sh;
  1161.         wheelreplim=4;
  1162.         wh_mask=0xffff;
  1163.         ro_rad=3<<sh;
  1164.         oty_fac=16;
  1165.         ot_size=4;
  1166.         etx_off=68;
  1167.         etx_f1=72;
  1168.         etx_f2=8;
  1169.         ety_off=150;
  1170.         ety_fac=8;
  1171.         tr_l=-1;
  1172.         tr_h=2;
  1173.         t_s=3;
  1174.         t_f=65;
  1175.         mincol=9;
  1176.         maxcol=15;
  1177.         endcol=13;
  1178.     }
  1179.     else if (mode==CGM)
  1180.     {
  1181.     sh=5;
  1182.         sc_xmax=319;
  1183.         sc_ymax=199;
  1184.         margin=5;
  1185.         baseline=195;
  1186.         spread=2;
  1187.         sp_vl=3;
  1188.         sp_vh=6;
  1189.         fl_vl=3;
  1190.         fl_vh=5;
  1191.         fl_mask=1;
  1192.         rk_vl=3;
  1193.         rk_vh=7;
  1194.         rktail_vl=-1;
  1195.         rktail_vh=1;
  1196.         ro_vl=3;
  1197.         ro_vh=6;
  1198.         wh_vl=2;
  1199.         wh_vh=4;
  1200.         wheelradius=6<<sh;
  1201.         wheelreplim=4;
  1202.         wh_mask=1;
  1203.         ro_rad=2<<sh;
  1204.         oty_fac=8;
  1205.         ot_size=3;
  1206.         etx_off=34;
  1207.         etx_f1=36;
  1208.         etx_f2=4;
  1209.         ety_off=75;
  1210.         ety_fac=6;
  1211.         tr_l=0;
  1212.         tr_h=0;
  1213.         t_s=2;
  1214.         t_f=130;
  1215.         mincol=1;
  1216.         maxcol=3;
  1217.         endcol=1;
  1218.     }
  1219.     else if (mode==TXTM)
  1220.     {
  1221.         sh=5;
  1222.         shx=7;
  1223.         shy=8;
  1224.         sc_xmax=319;
  1225.         sc_ymax=199;
  1226.         margin=0;
  1227.         baseline=195;
  1228.         spread=2;
  1229.         sp_vl=3;
  1230.         sp_vh=6;
  1231.         fl_vl=3;
  1232.         fl_vh=5;
  1233.         fl_mask=1;
  1234.         rk_vl=3;
  1235.         rk_vh=7;
  1236.         rktail_vl=-1;
  1237.         rktail_vh=1;
  1238.         ro_vl=3;
  1239.         ro_vh=7;
  1240.         wh_vl=2;
  1241.         wh_vh=4;
  1242.         wheelradius=6<<sh;
  1243.         wheelreplim=4;
  1244.         wh_mask=1;
  1245.         ro_rad=2<<sh;
  1246.         oty_fac=8;
  1247.         ot_size=3;
  1248.         etx_off=34;
  1249.         etx_f1=36;
  1250.         etx_f2=4;
  1251.         ety_off=75;
  1252.         ety_fac=8;
  1253.         tr_l=0;
  1254.         tr_h=0;
  1255.         t_s=2;
  1256.         t_f=130;
  1257.         mincol=9;
  1258.         maxcol=15;
  1259.         endcol=13;
  1260.     }
  1261.     if (mode==HGCM)
  1262.     {
  1263.     sh=5;
  1264.         sc_xmax=719;
  1265.         sc_ymax=347;
  1266.         margin=5;
  1267.         baseline=338;
  1268.         spread=5;
  1269.         sp_vl=3;
  1270.         sp_vh=8;
  1271.         fl_vl=4;
  1272.         fl_vh=8;
  1273.         fl_mask=0xffff;
  1274.         rk_vl=5;
  1275.         rk_vh=10;
  1276.         rktail_vl=-2;
  1277.         rktail_vh=2;
  1278.         ro_vl=6;
  1279.         ro_vh=11;
  1280.         wh_vl=4;
  1281.         wh_vh=7;
  1282.         wheelradius=10<<sh;
  1283.         wheelreplim=4;
  1284.         wh_mask=0xffff;
  1285.         ro_rad=3<<sh;
  1286.         oty_fac=16;
  1287.         ot_size=4;
  1288.     etx_off=76;
  1289.     etx_f1=81;
  1290.     etx_f2=9;
  1291.         ety_off=150;
  1292.         ety_fac=8;
  1293.         tr_l=-1;
  1294.         tr_h=2;
  1295.         t_s=3;
  1296.         t_f=65;
  1297.         mincol=1;
  1298.         maxcol=1;
  1299.         endcol=1;
  1300.     }
  1301. /* Set up the colour table*/
  1302.     for (im=0;im<=15;im++) col_table[im]=im;
  1303.     if (adapter==MDA)
  1304.     {
  1305.         mincol=1;
  1306.         maxcol=2;
  1307.         col_table[1]=7;
  1308.         col_table[2]=15;
  1309.     }
  1310. /* Calculate speed control parameters*/
  1311.     t_slope=(ref_60-ref_30)/30;
  1312.     t_intercept=2*ref_30-ref_60;
  1313.     indep=ref_count*(t_intercept+np*t_slope);
  1314.     if (mode==EGM) per_point=(ref_count*(ref_ega-ref_60))/120;
  1315.     else if (mode==CGM) per_point=(ref_count*(ref_cga-ref_30))/60;
  1316.     else if (mode==TXTM) per_point=(ref_count*(ref_text-ref_30))/60;
  1317.     else per_point=(ref_count*(ref_herc-ref_30))/60;
  1318. /*    printf("tot_loop %d indep %d per_point %d \n",tot_loop,indep,per_point);*/
  1319.     if (report) printf("Press any key to continue");
  1320.     if (report) getch();
  1321. /* Initialization*/
  1322.     if (mode==EGM)
  1323.     {
  1324.         setscreen(0x10);
  1325.     show=showega;
  1326.         egapointer=(char far *)0xa0000000;
  1327.     for (im=0;im<=349;im++) rowaddress[im]=im*80;
  1328.     }
  1329.     else if (mode==CGM)
  1330.     {
  1331.         setscreen(4);
  1332.     show=showcga;
  1333.         cgapointer0=(char far *)0xb8000000;
  1334.         cgapointer1=(char far *)0xba000000;
  1335.     for (im=0;im<=199;im++) rowaddress[im]=(im>>1)*320;
  1336.     }
  1337.     else if (mode==TXTM)
  1338.     {
  1339.         im=setscreen(3);
  1340.         if (im==7)
  1341.         {
  1342.             /* Monochrome display adapter*/
  1343.             txtpointer=(char far *)0xb0000000;
  1344.         }
  1345.         else
  1346.         {
  1347.             /* Cga etc*/
  1348.             txtpointer=(char far *)0xb8000000;
  1349.         }
  1350.     show=showtxt;
  1351.     for (im=0;im<=24;im++) rowaddress[im]=im*80;
  1352.         inr.h.ah=1;
  1353.         inr.h.ch=0xf;
  1354.         inr.h.cl=0xf;
  1355.         int86(0x10,&inr,&outr); /* Hide cursor*/
  1356.     }
  1357.     else if (mode==HGCM)
  1358.     {
  1359.     setscreen(-7);
  1360.     show=showhgc;
  1361.     hgcpointers[0]=(char far *)0xb0000000;
  1362.     hgcpointers[1]=(char far *)0xb0002000;
  1363.     hgcpointers[2]=(char far *)0xb0004000;
  1364.     hgcpointers[3]=(char far *)0xb0006000;
  1365.     for (im=0;im<=347;im++) rowaddress[im]=(im>>2)*90;
  1366.     }
  1367.     inr.x.ax=0x2c00;
  1368.     int86(0x21,&inr,&outr);
  1369.     srand(outr.x.dx); /* Seed random number generator*/
  1370.     setrange(&xmin,&xmax,margin<<sh,(sc_xmax-margin)<<sh);
  1371.     setrange(&ymin,&ymax,margin<<sh,(sc_ymax-margin)<<sh);
  1372.     for (im=0;im<NI;item_alive[im]=0,im++) /* Initialize items*/
  1373.     for (jm=0;jm<TP;alive[jm]=0,next[jm]=jm+1,jm++);
  1374. /* List of free points*/
  1375.     pfree=0;
  1376.     next[TP-1]=-1; /* End of list*/
  1377.     num_active=0;
  1378.     pactive=-1; /* List of active points*/
  1379.     num_dormant=0;
  1380.     for (im=0;im<NI;im++) pdormant[im]=-1; /* Lists of dormant points*/
  1381.     for (im=0;im<=90;im++)
  1382.     {
  1383.         sina[180+im]=sin(im/57.29578);
  1384.         sina[180+-im]=-sina[180+im];
  1385.         sina[180+180-im]=sina[180+im];
  1386.         sina[180+im-180]=-sina[180+im];
  1387.         cosa[180+im]=cos(im/57.29578);
  1388.         cosa[180+-im]=cosa[180+im];
  1389.         cosa[180+180-im]=-cosa[180+im];
  1390.         cosa[180+im-180]=-cosa[180+im];
  1391.     }
  1392.     for (im=181;im<=220;im++) /*Extend angle table for wheel rotation*/
  1393.     {
  1394.         sina[180+im]=sina[180+im-360];
  1395.         cosa[180+im]=cosa[180+im-360];
  1396.     }
  1397.     swap_flag=0; /* Flag for swapping cga colours*/
  1398.     swaplevel=10;
  1399.     cga_palette=rnd(0,1);
  1400.     swap_cga();
  1401.     burstwait=60-np; /* Wait before releasing burst*/
  1402.     wheelstepv=3;
  1403.     wheelsteplim=20;
  1404.     state2=1;
  1405.     capacity=0;
  1406.     clearscreen();
  1407.     setup_ega();
  1408.     synch=1; /* If non-zero, invokes timer tick synch*/
  1409.     if (testcapacity) fullspeed=1;
  1410.     if (fullspeed)
  1411.     {
  1412.         synch=0;
  1413.         tot_loop=0;
  1414.     }
  1415.     if (synch) ticks1=get_ticks();
  1416.     if (testcapacity) test_capacity();
  1417. /*    show(margin<<sh,margin<<sh,1,1,1);
  1418.     show((sc_xmax-margin)<<sh,margin<<sh,1,1,1);
  1419.     show(margin<<sh,(sc_ymax-margin)<<sh,1,1,1);
  1420.     show((sc_xmax-margin)<<sh,(sc_ymax-margin)<<sh,1,1,1);
  1421.     while (!kbhit());*/
  1422.     do
  1423.     {
  1424.         opening_screen();
  1425.         count=0;
  1426.         inr.h.ah=0x2c;
  1427.         int86(0x21,&inr,&outr); /* Get start time*/
  1428.         hs=outr.h.ch;
  1429.         ms=outr.h.cl;
  1430.         ss=outr.h.dh;
  1431.         if (script==STANDARD)
  1432.         {
  1433.             multiple(flare,3,1,200,20,150,999);
  1434.             multiple(spurt,1,1,450,20,320+3*np,swaplevel+30);
  1435.             multiple(wheel,2,1,270,20,240,swaplevel+30);
  1436.             multiple(burst,5,1,100,10,75,swaplevel+30);
  1437.             multiple(rocket,5,3,100,10,0,swaplevel+30);
  1438.             multiple(burst,5,1,100,10,35,swaplevel+10);
  1439.             multiple(spurt,2,1,450,20,500,swaplevel+10);
  1440.             multiple(flare,4,1,200,20,150,swaplevel+30);
  1441.             swaplevel=0; /* Delay colour change while flare still active*/
  1442.             multiple(burst,5,1,100,10,25,swaplevel+30);
  1443.             swaplevel=10;
  1444.             multiple(roman,5,3,100,10,60,swaplevel+30);
  1445.             swap_cga();
  1446.             /*Set up for finale*/
  1447.             state2=0;
  1448.             burstlife=20;
  1449.             swaplevel=-999;
  1450.             startup(burst,sc_xmax/4,4*sc_ymax/7,100,1,3,3,5,-1);
  1451.             process(30,-1);
  1452.             startup(burst,8*sc_xmax/10,2*sc_ymax/7,100,1,3,3,5,-1);
  1453.             process(50,-1);
  1454.             startup(burst,4*sc_xmax/10,sc_ymax/7,100,1,3,3,5,-1);
  1455.             process(180,-1);
  1456.             state2=1;
  1457.             burstlife=10;
  1458.             swaplevel=10;
  1459.             clearscreen(); /*End of finale*/
  1460.             setup_ega();
  1461.         }
  1462.         else
  1463.         {
  1464.             multiple(flare,3,1,200,20,150,999);
  1465.             multiple(spurt,1,1,450,20,320+3*np,swaplevel+30);
  1466.             multiple(wheel,1,1,270,20,240,swaplevel+30);
  1467.             multiple(burst,5,1,100,20,75,swaplevel+30);
  1468.             multiple(rocket,5,3,100,25,20,swaplevel+30);
  1469.             multiple(burst,5,1,100,20,35,swaplevel+10);
  1470.             multiple(spurt,2,1,450,20,500,swaplevel+10);
  1471.             multiple(flare,2,1,200,20,150,swaplevel+30);
  1472.             swaplevel=0; /* Delay colour change while flare still active*/
  1473.             multiple(burst,5,1,100,20,25,swaplevel+30);
  1474.             swaplevel=10;
  1475.             multiple(roman,3,3,100,25,50,swaplevel+30);
  1476.             swap_cga();
  1477.             /*Set up for finale*/
  1478.             state2=0;
  1479.             burstlife=20;
  1480.             swaplevel=-999;
  1481.             startup(burst,sc_xmax/4,4*sc_ymax/7,100,1,3,3,5,-1);
  1482.             process(30,-1);
  1483.             startup(burst,8*sc_xmax/10,2*sc_ymax/7,100,1,3,3,5,-1);
  1484.             process(50,-1);
  1485.             startup(burst,4*sc_xmax/10,sc_ymax/7,100,1,3,3,5,-1);
  1486.             process(180,-1);
  1487.             state2=1;
  1488.             burstlife=10;
  1489.             swaplevel=10;
  1490.             clearscreen(); /*End of finale*/
  1491.             setup_ega();
  1492.         }
  1493.     }
  1494.     while (continuous);
  1495.     terminate();
  1496. } /*End main*/
  1497.